#include "StdAfx.h"
#include "elliptic_curve.h"
#define sqr(x) ((x)*(x))

ec_point::ec_point(const elliptic_curve * const ec, bool is_inf)
	:container(ec), inf(is_inf), x(0), y(0)
{
}
ec_point::ec_point(const elliptic_curve * const ec, const double _x, const double _y)
	:container(ec), inf(false), x(_x), y(_y)
{
}
ec_point ec_point::operator +(const ec_point p)
{
	// same curve?
	if(!same_curve(p)) 
		throw "Only points on the same curve allowed to add";

	// wheather one of points is infinity
	if(this->inf) return p;
	if(p.inf) return *this;

	
	if(*this == -p)
		return ec_point(container,true); // result is infinity point 
	
	double _x,_y,_alpha;
	
	if(*this == p) // tangent
	{
		_alpha = (3 * sqr(x) + container->a()) / (2 * y);
	}
	else // p != +/- q
	{
		_alpha = (p.y - y) / (p.x - x);
	}
	_x = sqr(_alpha) - p.x - x;
	_y = -y + _alpha * (x - _x);
	return ec_point(container,_x,_y);
}
ec_point operator -(const ec_point p)
{
	if(p.inf) return p;
	return ec_point(p.container,p.x,-p.y);
}
bool ec_point::operator ==(const ec_point p)
{
	return same_curve(p) && (this->x==p.x) && (this->y==p.y);
}

inline bool ec_point::same_curve(const ec_point p)
{
	return container->contains(p);
}

elliptic_curve::elliptic_curve(const double a, const double b)
	:_a(a),_b(b)
{
}


#define EC_VALUE(x,y,a,b) ((y)*(y) - (x)*(x)*(x) - (a)*(x) - (b))
bool elliptic_curve::contains(const ec_point p) const
{
	return (EC_VALUE(p.x,p.y,_a,_b)==0);
}
double elliptic_curve::a() const
{
	return _a;
}
double elliptic_curve::b() const
{
	return _b;
}
